import requests
import json
from typing import Optional, Union, Dict, Any, List

from utils.logger import logger
from config.env_config import env_config
from utils.auth_handlers import BaseAuthHandler


# 配置日志格式
class BaseHTTPRequest:
    
    def __init__(self, env: str = "qiming-test3", service: Optional[str] = None, 
                 version: Optional[str] = "v1", base_url: Optional[str] = None,
                 auth_handler: Optional[BaseAuthHandler] = None):
        """
        初始化基础HTTP请求类
        
        参数:
            env (str, optional): 环境名称，默认为"qiming-test3"
            service (str, optional): 服务名称，默认为None
            version (str, optional): 版本号，默认为"v1"
            base_url (str, optional): 自定义基础URL，优先级高于env+service组合
            auth_handler (BaseAuthHandler, optional): 认证处理器
        """
        if base_url:
            self.base_url = base_url
        else:
            host = env_config.get_base_url(env)
            if service:
                self.base_url = f"{host}/{service}/{version}"
            else:
                self.base_url = host
        
        self.session = requests.Session()
        self.auth_handler = auth_handler
    
    def set_auth_handler(self, auth_handler: BaseAuthHandler):
        """
        设置认证处理器
        
        参数:
            auth_handler: 认证处理器实例
        """
        self.auth_handler = auth_handler
        
    def _log_request(self, method: str, url: str, **kwargs) -> None:
        """
        记录请求信息到日志
        
        参数:
            method: 请求方法
            url: 完整请求URL
            **kwargs: 其他请求参数
        """
        logger.info(f"发起 {method} 请求: {url}")
        
        # 记录请求头
        if 'headers' in kwargs:
            logger.info("请求头:")
            for key, value in kwargs['headers'].items():
                # # 隐藏敏感信息
                # if key.lower() in ['authorization', 'x-signature', 'x-mfa-code']:
                #     logger.info(f"  {key}: ***")
                # else:
                #     logger.info(f"  {key}: {value}")
                logger.info(f"  {key}: {value}")
        # 记录请求参数
        if 'params' in kwargs and kwargs['params']:
            logger.info(f"请求参数: {kwargs['params']}")
                
        # 记录请求数据
        if 'data' in kwargs and kwargs['data']:
            logger.info("请求数据 (form-data):")
            for key, value in kwargs['data'].items():
                logger.info(f"  {key}: {value}")
                
        if 'json' in kwargs and kwargs['json']:
            # 使用ensure_ascii=False确保中文正常显示
            logger.info(f"请求JSON数据: {json.dumps(kwargs['json'], ensure_ascii=False)}")
            
        if 'files' in kwargs and kwargs['files']:
            logger.info("上传文件:")
            for key, file_info in kwargs['files'].items():
                logger.info(f"  文件名: {file_info[0]}, 类型: {file_info[1].__class__.__name__}")
    
    def _log_response(self, response: requests.Response) -> None:
        """
        记录响应信息到日志
        
        参数:
            response: 响应对象
        """
        logger.info(f"响应状态码: {response.status_code}")
        
        # 记录request_id
        if 'x-request-id' in response.headers:
            logger.info(f"request_id: {response.headers['x-request-id']}")
            
        # 记录响应头
        logger.debug("响应头:")
        for key, value in response.headers.items():
            logger.debug(f"  {key}: {value}")
            
        # 记录响应内容
        try:
            json_response = response.json()
            # 使用ensure_ascii=False确保中文正常显示
            logger.info(f"响应JSON内容: {json.dumps(json_response, ensure_ascii=False)}")
        except json.JSONDecodeError:
            logger.info(f"响应文本内容: {response.text[:500]}")  # 只记录前500个字符
            
    def _handle_exception(self, e: Exception, response: Optional[requests.Response] = None) -> Dict[str, Any]:
        """
        处理请求异常
        
        参数:
            e: 异常对象
            response: 响应对象
        返回:
            包含错误信息的字典
        """
        if isinstance(e, requests.exceptions.HTTPError):
            logger.error(f"HTTP错误: {str(e)}")
            if response:
                logger.error(f"响应状态码: {response.status_code}")
                logger.error(f"响应内容: {response.text}")
        elif isinstance(e, requests.exceptions.ConnectionError):
            logger.error("连接错误: 无法连接到服务器")
        elif isinstance(e, requests.exceptions.Timeout):
            logger.error("请求超时: 服务器未在规定时间内响应")
        elif isinstance(e, requests.exceptions.RequestException):
            logger.error(f"请求异常: {str(e)}")
        else:
            logger.error(f"未知错误: {str(e)}")
            
        return {
            "error": str(e),
            "success": False,
            "status_code": response.status_code if response else None
        }
    
    def _process_url(self, endpoint: str) -> str:
        """
        处理URL拼接
        
        参数:
            endpoint: 接口路径
        返回:
            完整的URL
        """
        if self.base_url:
            return f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}"
        return endpoint
    
    def _prepare_request_data(self, headers: Optional[Dict[str, str]] = None, 
                             params: Optional[Dict[str, Any]] = None, **kwargs) -> Dict[str, Any]:
        """
        准备请求数据并应用认证
        
        参数:
            headers: 请求头
            params: 请求参数
            **kwargs: 其他请求参数
        返回:
            处理后的请求数据
        """
        request_data = {
            'headers': headers or {},
            'params': params
        }
        
        # 添加其他请求参数
        for key, value in kwargs.items():
            if value is not None:
                request_data[key] = value
        
        # 应用认证处理器
        if self.auth_handler:
            request_data = self.auth_handler.apply_auth(request_data)
        
        return request_data

    def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
        """
        处理响应数据
        
        参数:
            response: 响应对象
        """
        self._log_response(response)
        
        # 处理HTTP错误状态码
        if response.status_code >= 400:
            error_info = {
                "error": f"HTTP {response.status_code} Error",
                "success": False,
                "status_code": response.status_code,
                "response_text": response.text
            }
            logger.error(f"HTTP错误: {response.status_code} - {response.text}")
            return error_info

        # 处理响应数据，优先尝试解析为JSON，如果失败则以文本形式返回
        try:
            json_data = response.json()
            # 处理中文Unicode编码
            if isinstance(json_data, dict) and "data" in json_data and isinstance(json_data["data"], str):
                # 尝试将Unicode编码转为中文字符
                try:
                    # 确保编码正确
                    if '\\u' in json_data["data"]:
                        json_data["data"] = json_data["data"].encode('utf-8').decode('unicode_escape')
                except:
                    # 如果解码失败，保持原样
                    pass

            return json_data
        except json.JSONDecodeError:
            return {
                "success": True,
                "data": response.text,
                "status_code": response.status_code
            }
    
    def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None, 
            headers: Optional[Dict[str, str]] = None, **kwargs) -> Dict[str, Any]:
        """
        发送GET请求
        
        参数:
            endpoint: 接口路径
            params: 请求参数
            headers: 请求头
            **kwargs: 其他requests.get支持的参数
            
        返回:
            包含响应数据或错误信息的字典
        """
        url = self._process_url(endpoint)
        response = None
        
        try:
            request_data = self._prepare_request_data(headers=headers, params=params, **kwargs)
            
            self._log_request('GET', url, **request_data)
            response = self.session.get(url, **request_data)
            return self._handle_response(response)
        except Exception as e:
            return self._handle_exception(e, response)
    
    def post(self, endpoint: str, data: Optional[Union[Dict[str, Any], List[Any]]] = None,
             json: Optional[Union[Dict[str, Any], List[Any]]] = None,
             files: Optional[Dict[str, Any]] = None,
             headers: Optional[Dict[str, str]] = None, 
             params: Optional[Dict[str, Any]] = None, **kwargs) -> Dict[str, Any]:
        """
        发送POST请求
        
        参数:
            endpoint: 接口路径
            data: 表单数据
            json: JSON数据
            files: 文件上传数据
            headers: 请求头
            params: 请求参数
            **kwargs: 其他requests.post支持的参数
            
        返回:
            包含响应数据或错误信息的字典
        """
        url = self._process_url(endpoint)
        response = None
        
        try:
            request_data = self._prepare_request_data(
                headers=headers, params=params, data=data, json=json, files=files, **kwargs
            )
            
            # 设置Content-Type
            if files and 'Content-Type' in request_data['headers']:
                # 文件上传时需要移除Content-Type，让requests自动设置
                del request_data['headers']['Content-Type']
            elif json and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/json'
            elif data and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
                
            self._log_request('POST', url, **request_data)
            response = self.session.post(url, **request_data)
            return self._handle_response(response)
        except Exception as e:
            return self._handle_exception(e, response)
    
    def put(self, endpoint: str, data: Optional[Dict[str, Any]] = None,
            json: Optional[Dict[str, Any]] = None,
            headers: Optional[Dict[str, str]] = None,
            params: Optional[Dict[str, Any]] = None, **kwargs) -> Dict[str, Any]:
        """
        发送PUT请求
        
        参数:
            endpoint: 接口路径
            data: 表单数据
            json: JSON数据
            headers: 请求头
            params: 请求参数
            **kwargs: 其他requests.put支持的参数
            
        返回:
            包含响应数据或错误信息的字典
        """
        url = self._process_url(endpoint)
        response = None
        
        try:
            request_data = self._prepare_request_data(
                headers=headers, params=params, data=data, json=json, **kwargs
            )
            
            # 设置Content-Type
            if json and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/json'
            elif data and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
                
            self._log_request('PUT', url, **request_data)
            response = self.session.put(url, **request_data)
            return self._handle_response(response)
        except Exception as e:
            return self._handle_exception(e, response)
    
    def delete(self, endpoint: str, params: Optional[Dict[str, Any]] = None,
               headers: Optional[Dict[str, str]] = None, **kwargs) -> Dict[str, Any]:
        """
        发送DELETE请求
        
        参数:
            endpoint: 接口路径
            params: 请求参数
            headers: 请求头
            **kwargs: 其他requests.delete支持的参数
            
        返回:
            包含响应数据或错误信息的字典
        """
        url = self._process_url(endpoint)
        response = None
        
        try:
            request_data = self._prepare_request_data(headers=headers, params=params, **kwargs)
            
            self._log_request('DELETE', url, **request_data)
            response = self.session.delete(url, **request_data)
            return self._handle_response(response)
        except Exception as e:
            return self._handle_exception(e, response)
    
    def patch(self, endpoint: str, data: Optional[Dict[str, Any]] = None,
              json: Optional[Dict[str, Any]] = None,
              headers: Optional[Dict[str, str]] = None,
              params: Optional[Dict[str, Any]] = None, **kwargs) -> Dict[str, Any]:
        """
        发送PATCH请求
        
        参数:
            endpoint: 接口路径
            data: 表单数据
            json: JSON数据
            headers: 请求头
            params: 请求参数
            **kwargs: 其他requests.patch支持的参数
            
        返回:
            包含响应数据或错误信息的字典
        """
        url = self._process_url(endpoint)
        response = None
        
        try:
            request_data = self._prepare_request_data(
                headers=headers, params=params, data=data, json=json, **kwargs
            )
            
            # 设置Content-Type
            if json and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/json'
            elif data and 'Content-Type' not in request_data['headers']:
                request_data['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
                
            self._log_request('PATCH', url, **request_data)
            response = self.session.patch(url, **request_data)
            return self._handle_response(response)
        except Exception as e:
            return self._handle_exception(e, response)